﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting;
using com.eforceglobal.crux.configuration;
using com.eforceglobal.crux.logging;
using com.eforceglobal.crux.logging.Enums;
using com.eforceglobal.crux.web.wrokflows.DTOs;
using com.eforcegloabal.crux.web.wrokflows;

namespace com.eforceglobal.crux.web.wrokflows
{
    public class WorkflowManager
    {
        BusinessObjectsDataContext bc = new BusinessObjectsDataContext(
            CruxConfigurationManager.GetCruxDBConnectionString());

        public int CreateWorkflowInstance(string WorkflowName, string Comments, string UserId, object BusinessObjectData)
        {
            try
            {
                Workflow workflow = ConfigParser.GetWorkflowConfiguration(WorkflowName);
                WorkflowInstance workflowInstance = new WorkflowInstance();
                workflowInstance.WorkflowName = workflow.WorkflowName;
                workflowInstance.ActivityName = workflow.StartActivity.ActivityName;
                workflowInstance.StateName = workflow.StartActivity.State;
                workflowInstance.LastModifiedBy = UserId;
                workflowInstance.LastModifiedOn = DateTime.Now;
                workflowInstance.Comments = Comments;
                Action action = workflow.StartActivity.DefaultAction;
                if (action != null && !string.IsNullOrEmpty(action.ActionDll) && !string.IsNullOrEmpty(action.ActionClass))
                    FireActionOnWorkflowInstance(workflowInstance, action.ActionName, BusinessObjectData, UserId);
                bc.WorkflowInstances.InsertOnSubmit(workflowInstance);
                bc.SubmitChanges();
                return workflowInstance.WorkflowInstanceId;
            }
            catch(Exception ex)
            {
                ApplicationLogger
                    .LogApplicationMessage(ex.Message, ApplicationLogType.Workflow, ex.StackTrace);
                throw;
            }
        }

        public int CreateWorkflowInstance(string WorkflowName, string ActivityName, string StateName, string Comments, string UserId, object BusinessObjectData)
        {
            try
            {
                Workflow workflow = ConfigParser.GetWorkflowConfiguration(WorkflowName);
                WorkflowInstance workflowInstance = new WorkflowInstance
                {
                    WorkflowName = workflow.WorkflowName,
                    ActivityName = ActivityName,
                    StateName = StateName,
                    LastModifiedBy = UserId,
                    LastModifiedOn = DateTime.Now,
                    Comments = Comments
                };
                bc.WorkflowInstances.InsertOnSubmit(workflowInstance);
                bc.SubmitChanges();
                return workflowInstance.WorkflowInstanceId;
            }
            catch (Exception ex)
            {
                ApplicationLogger
                    .LogApplicationMessage(ex.Message, ApplicationLogType.Workflow, ex.StackTrace);
                throw;
            }
        }


        private void FireActionOnWorkflowInstance(WorkflowInstance workFlowInstance, string ActionName, Object BusinessData, string UserId)
        {
            Action action = ConfigParser.GetAction(workFlowInstance.WorkflowName, workFlowInstance.ActivityName, ActionName);
            InvokePluggableAction(action, BusinessData, workFlowInstance);
            Activity resultantActivity = ConfigParser.GetActivity(workFlowInstance.WorkflowName, action.ResultantAcitivity);
            workFlowInstance.ActivityName = resultantActivity.ActivityName;
            workFlowInstance.StateName = resultantActivity.State;
            workFlowInstance.LastModifiedBy = UserId;
            workFlowInstance.LastModifiedOn = DateTime.Now;
            bc.SubmitChanges();
        }

        public void FireActionOnWorkflowInstance(int workFlowInstanceId, string ActionName, string UserId, Object BusinessData, bool AddActionToAuditTrail)
        {
            WorkflowInstance workflowInsatance = GetDbWorkflowInstance(workFlowInstanceId);
            if (AddActionToAuditTrail)
                AddToAuditTrail(workflowInsatance);
            FireActionOnWorkflowInstance(workflowInsatance, ActionName, BusinessData,UserId);
        }

        public void TransmitWorkflowToState(int WorkflowInstanceId, string ActivityName, string StateName)
        {
            WorkflowInstance workflowInsatance = bc.WorkflowInstances.Single(p=>p.WorkflowInstanceId==WorkflowInstanceId);
            workflowInsatance.ActivityName = ActivityName;
            workflowInsatance.StateName = StateName;
            bc.SubmitChanges();
        }

        private void AddToAuditTrail(WorkflowInstance workflowInstance)
        {
            WorkflowInstanceAuditTrail workflowInstanceAuditTrail = new WorkflowInstanceAuditTrail();
            workflowInstanceAuditTrail.WorkflowInstanceId = workflowInstance.WorkflowInstanceId;
            workflowInstanceAuditTrail.WorkflowName = workflowInstance.WorkflowName;
            workflowInstanceAuditTrail.ActivityName = workflowInstance.ActivityName;
            workflowInstanceAuditTrail.Comments = workflowInstance.Comments;
            workflowInstanceAuditTrail.LastModifiedBy = workflowInstance.LastModifiedBy;
            workflowInstanceAuditTrail.LastModifiedOn = workflowInstance.LastModifiedOn;
            workflowInstanceAuditTrail.StateName = workflowInstance.StateName;
            workflowInstanceAuditTrail.WorkflowName = workflowInstance.WorkflowName;
            bc.WorkflowInstanceAuditTrails.InsertOnSubmit(workflowInstanceAuditTrail);
        }

        

        private void InvokePluggableAction(Action action, Object BusinessData, WorkflowInstance workflowInstance)
        {
            if (!string.IsNullOrEmpty(action.ActionDll) && !string.IsNullOrEmpty(action.ActionClass))
            {
                ObjectHandle objectHandle = Activator.CreateInstance(action.ActionDll, action.ActionClass);
                if (objectHandle != null)
                {
                    ICruxActivity activity = (ICruxActivity)objectHandle.Unwrap();
                    activity.Action(BusinessData, action.ActionName, workflowInstance.WorkflowInstanceId);
                }
            }
        }

        private WorkflowInstance GetDbWorkflowInstance(int WorkflowInstanceId)
        {
          return bc.WorkflowInstances.Single(p => p.WorkflowInstanceId == WorkflowInstanceId);
        }

        public IEnumerable<WorkflowInstanceInformation> GetWorkflowInstancesByState(string StateName)
        {
            IEnumerable<WorkflowInstanceInformation> workflowInstances = from allinstances in bc.WorkflowInstances
                                                              where allinstances.StateName == StateName
                                                              select WorkflowClassConverter.CopyWorkflowInstanceToWorkflowInstanceInformation(allinstances);
            return workflowInstances;
        }

        public WorkflowInstanceInformation GetWorkflowInstance(int WorkflowInstanceId)
        {
            return WorkflowClassConverter.CopyWorkflowInstanceToWorkflowInstanceInformation(
            GetDbWorkflowInstance(WorkflowInstanceId));
        }



        public void DeleteWorkflow(int workflowInstanceid)
        {
            WorkflowInstance workflowInstance = GetDbWorkflowInstance(workflowInstanceid);
            bc.WorkflowInstances.DeleteOnSubmit(workflowInstance);
            bc.SubmitChanges();
        }

        
    }
}
